#include "StdAfx.h"
#include "TypeTracker.h"

#include <sstream>
#include "assert.h"

TypeTracker::TypeTracker(void) : m_pClientData(NULL), m_pClassLoadedCallback(NULL)
{
}

void TypeTracker::Initialize(CComPtr<ICorProfilerInfo2> pCorProfilerInfo)
{
	m_pCorProfilerInfo = pCorProfilerInfo;
}

void TypeTracker::RegisterForClassLoad(ClassLoaded pClassLoadedFunc, void *data)
{
	m_pClientData = data;
	m_pClassLoadedCallback = pClassLoadedFunc;
}

HRESULT TypeTracker::ClassLoadFinished(ClassID classId,	HRESULT hrStatus)
{
	CLRClass clrClass;
	HRESULT hr = CreateAndAddToCache(classId, &clrClass);

	if (m_pClassLoadedCallback != NULL)
	{
		m_pClassLoadedCallback(clrClass, m_pClientData);
	}

	return hr;
}

HRESULT TypeTracker::GetCLRClassFor(ClassID classId, CLRClass *pCLRClass)
{
	//OutputDebugStringA("Gee ClassID");
	TYPES_TO_WATCH_ITERATOR iter = m_TypesCache.find(classId);

	//OutputDebugStringA("Find Completed");

	if (iter != m_TypesCache.end())
	{
		*pCLRClass = iter->second;
		return S_OK;
	}

	HRESULT hr = CreateAndAddToCache(classId, pCLRClass);

	//assert(SUCCEEDED(hr));

	/*std::ostringstream str;
	str << hr;
	OutputDebugStringA(str.str().c_str());*/

	return hr;
}

HRESULT TypeTracker::CreateAndAddToCache(ClassID classId, CLRClass *pCLRClass)
{
	//OutputDebugString(L"Before Loading Type");

	ModuleID moduleId = 0;
	mdTypeDef typeDefToken = 0;

	//ofs << "Loaded " << classId;
	//ofs.flush();

	HRESULT hr = m_pCorProfilerInfo->GetClassIDInfo(classId, &moduleId, &typeDefToken);

	//OutputDebugStringA("After GetClassIDInfo");

	if (FAILED(hr))
		return hr;

	CComPtr<IMetaDataImport2> metaDataGetter = NULL;
	hr = m_pCorProfilerInfo->GetModuleMetaData(moduleId, ofRead, IID_IMetaDataImport2, (IUnknown **)&metaDataGetter);

	if (FAILED(hr))
		return hr;

	WCHAR buf[512];
	ULONG typeNameLength;
	DWORD flags = 0;
	mdToken baseTypeDef = 0;

	hr = metaDataGetter->GetTypeDefProps(typeDefToken, buf, sizeof(buf)/sizeof(buf[0]), &typeNameLength, &flags, &baseTypeDef);

	if (FAILED(hr))
		return hr;

	CLRClass clrClass;
	clrClass.classId = classId;
	clrClass.metaDataToken = typeDefToken;
	clrClass.fullTypeName = std::wstring(buf);

	bool hasFinalizer = true;
	//if (SUCCEEDED(DoesTypeHaveFinalizer(classId, &hasFinalizer)))
		clrClass.hasFinalizer = hasFinalizer;

	m_TypesCache[classId] = clrClass;

	*pCLRClass = clrClass;

	//OutputDebugStringA("After Loading Type");
	return S_OK;
}

HRESULT TypeTracker::DoesTypeHaveFinalizer(CComPtr<IMetaDataImport2> pMetaDataGetter, ClassID classId, mdToken typeDefToken, bool *result)
{
	*result = true;
	return S_OK;
}

TypeTracker::~TypeTracker(void)
{
}
